package com.campus.delivery.handler;

import cn.hutool.json.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 原生WebSocket处理器
 * 支持uni-app小程序的原生WebSocket连接
 */
@Component
@Slf4j
public class NativeWebSocketHandler implements WebSocketHandler {

    private final ObjectMapper objectMapper = new ObjectMapper();
    
    // 存储所有WebSocket会话
    private static final CopyOnWriteArraySet<WebSocketSession> sessions = new CopyOnWriteArraySet<>();
    
    // 存储配送员ID与WebSocket会话的映射关系
    private static final ConcurrentHashMap<Integer, WebSocketSession> deliverySessions = new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.add(session);
        log.info("WebSocket连接建立，会话ID: {}", session.getId());
        
        // 发送连接成功消息
        sendMessage(session, createMessage("connection", "WebSocket连接成功", null));
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        String payload = message.getPayload().toString();
        log.info("收到WebSocket消息: {}", payload);
        
        try {
            JsonNode jsonNode = objectMapper.readTree(payload);
            String type = jsonNode.get("type").asText();
            
            switch (type) {
                case "test":
                    handleTestMessage(session, jsonNode);
                    break;
                case "heartbeat":
                    handleHeartbeat(session, jsonNode);
                    break;
                case "delivery_connect":
                    handleDeliveryConnect(session, jsonNode);
                    break;
                default:
                    log.warn("未知的消息类型: {}", type);
                    break;
            }
        } catch (Exception e) {
            log.error("处理WebSocket消息失败: {}", e.getMessage(), e);
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("WebSocket传输错误，会话ID: {}, 错误: {}", session.getId(), exception.getMessage(), exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        sessions.remove(session);
        
        // 从配送员会话映射中移除
        deliverySessions.entrySet().removeIf(entry -> entry.getValue().equals(session));
        
        log.info("WebSocket连接关闭，会话ID: {}, 关闭状态: {}", session.getId(), closeStatus);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * 处理测试消息
     */
    private void handleTestMessage(WebSocketSession session, JsonNode jsonNode) throws IOException {
        Integer deliveryId = jsonNode.get("deliveryId").asInt();
        log.info("收到测试消息，配送员ID: {}", deliveryId);
        
        // 建立配送员ID与会话的映射关系
        deliverySessions.put(deliveryId, session);
        
        // 响应测试消息
        sendMessage(session, createMessage("test_response", "测试消息接收成功", deliveryId));
    }

    /**
     * 处理心跳消息
     */
    private void handleHeartbeat(WebSocketSession session, JsonNode jsonNode) throws IOException {
        log.debug("收到心跳消息");
        
        // 响应心跳
        sendMessage(session, createMessage("heartbeat_response", "心跳正常", null));
    }

    /**
     * 处理配送员连接消息
     */
    private void handleDeliveryConnect(WebSocketSession session, JsonNode jsonNode) throws IOException {
        Integer deliveryId = jsonNode.get("deliveryId").asInt();
        log.info("配送员连接，配送员ID: {}", deliveryId);
        
        // 建立配送员ID与会话的映射关系
        deliverySessions.put(deliveryId, session);
        
        // 响应连接成功
        sendMessage(session, createMessage("delivery_connect_response", "配送员连接成功", deliveryId));
    }

    /**
     * 向指定配送员发送出餐通知
     */
    public void sendMealReadyNotification(Integer deliveryId, String mealMessage) {
        WebSocketSession session = deliverySessions.get(deliveryId);
        if (session != null && session.isOpen()) {
            try {
                String message = createMessage("meal_ready", mealMessage, deliveryId);
                sendMessage(session, message);
                log.info("向配送员{}发送出餐通知成功: {}", deliveryId, mealMessage);
            } catch (IOException e) {
                log.error("向配送员{}发送出餐通知失败: {}", deliveryId, e.getMessage(), e);
            }
        } else {
            log.warn("配送员{}的WebSocket会话不存在或已关闭，无法发送出餐通知", deliveryId);
        }
    }

    /**
     * 广播系统通知给所有在线配送员
     */
    public void broadcastSystemNotification(String message) {
        String jsonMessage = createMessage("system_notification", message, null);
        broadcastToAll(jsonMessage);
    }
    
    /**
     * 广播订单状态变更给所有在线配送员
     */
    public void broadcastOrderStatusChange(String orderId, Integer newDeliveryProcess, Integer grabbedByDeliveryId) {
        String jsonMessage = createOrderStatusMessage(orderId, newDeliveryProcess, grabbedByDeliveryId);
        broadcastToAll(jsonMessage);
    }
    
    /**
     * 广播消息给所有在线会话
     */
    private void broadcastToAll(String message) {
        for (WebSocketSession session : sessions) {
            if (session.isOpen()) {
                try {
                    sendMessage(session, message);
                } catch (IOException e) {
                    log.error("广播消息失败，会话ID: {}, 错误: {}", session.getId(), e.getMessage(), e);
                }
            }
        }
        log.info("广播消息: {}", message);
    }


    /**
     * 发送消息到WebSocket会话
     */
    private void sendMessage(WebSocketSession session, String message) throws IOException {
        if (session.isOpen()) {
            session.sendMessage(new TextMessage(message));
        }
    }

    /**
     * 创建JSON格式的消息
     */
    private String createMessage(String type, String content, Integer deliveryId) {
        try {
            JSONObject json = new JSONObject();
            json.put("type", type);
            json.put("content", content);
            if (deliveryId != null) {
                json.put("deliveryId", deliveryId);
            }
            json.put("timestamp", System.currentTimeMillis());
            return json.toString();
        } catch (Exception e) {
            log.error("创建消息失败: {}", e.getMessage(), e);
            return "{\"type\":\"error\",\"content\":\"消息创建失败\"}";
        }
    }

    /**
     * 创建订单状态变更消息
     */
    private String createOrderStatusMessage(String orderId, Integer newDeliveryProcess, Integer grabbedByDeliveryId) {
        try {
            JSONObject json = new JSONObject();
            json.put("type", "order_status_change");
            json.put("orderId", orderId);
            json.put("newDeliveryProcess", newDeliveryProcess);
            json.put("grabbedByDeliveryId", grabbedByDeliveryId);
            json.put("timestamp", System.currentTimeMillis());
            return json.toString();
        } catch (Exception e) {
            log.error("创建订单状态变更消息失败: {}", e.getMessage(), e);
            return "{\"type\":\"error\",\"content\":\"订单状态变更消息创建失败\"}";
        }
    }

    /**
     * 获取在线配送员数量
     */
    public int getOnlineDeliveryCount() {
        return deliverySessions.size();
    }

    /**
     * 获取总连接数
     */
    public int getTotalConnectionCount() {
        return sessions.size();
    }
}